// ==UserScript==
// @name		Super Scroller V2
// @namespace	http://mx-userscripts.googlecode.com/svn/trunk/
// @Author		JarC
// @Version		2.0
// @include		*
// @exclude
// ==/UserScript==

/*
parts based on:
Smooth Scroller by Dezinerfolio Inc. (midart@gmail.com)
http://www.dezinerfolio.com/2007/08/08/df-javascript-smooth-scroll
*/

var sS_uA = navigator.userAgent;
var is = {IE: (document.all && !window.opera),WebKit: RegExp(" AppleWebKit/").test(sS_uA),MobileSafari: RegExp("Apple.*Mobile.*Safari").test(sS_uA)}
var sS =
{
	X:null,
	Y:null,
	newY:null,
	snooze:500,
	delta:[null,null],
	step:1,
	delay:0,
	speed:15,
	scaling:2,
	offsetTop:0,
	jumpTarget:0,
	modifier:true,
	button:null,
	thumbFace:null,
	scrollerImg:null,
	docBody:null,
	winWide:0,
	winHigh:0,
	deadVZone:0,
	overlap:30,
	multiMon:1,
	hoverWidth:0,
	Hovering:false,
	Dragging:false,
	JumpMove:false,
	NoGoTags:',HTML,A,AREA,IMG,OBJECT,EMBED,',
	FormTags:',INPUT,SELECT,TEXTAREA,BUTTON,LABEL,',

	init : function()
	{
	if (is.MobileSafari) return;
		if(is.WebKit) sS.button = 0;
		else sS.button = 1;

		if(sS.multiMon) sS.hoverWidth = 12;
		else sS.hoverWidth = 17;

		sS.docBody = document.body;

		if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )
			sS.docBody = document.documentElement;
		else
		if( document.body && ( document.body.clientWidth || document.body.clientHeight ) )
			sS.docBody = document.body;

		sS.onResize();

		sS.addEvent(document,'beforeunload',sS.beforeUnload);
		sS.addEvent(document,'mousewheel',sS.onWheel);
		sS.addEvent(document,'mousedown',sS.onMDown);
		sS.addEvent(document,'mousemove',sS.onMMove);
		sS.addEvent(document,'mouseup',sS.onMUp);
		sS.addEvent(document,'keydown',sS.onKDown);
		sS.addEvent(document,'keyup',sS.onKUp);

		sS.addEvent(window,'resize',sS.onResize);

		var s = sS.getScrollPosition();
		if((s.h > sS.winHigh) && (sS.winHigh > 200))
		{
			sS.injectMap();
			sS.injectImage();
			if((document.compatMode!='CSS1Compat')) sS.addEvent(window,'scroll',sS.onScroll);
		}
	},

	injectImage : function()
	{
		var scrollButton;
		scrollButton =  document.createElement('img');
		scrollButton.id = 'superScrollerImg';
		scrollButton.src= '';

		if(document.compatMode!='CSS1Compat')
			scrollButton.style.position = 'absolute';
		else
			scrollButton.style.position = 'fixed';

		scrollButton.style.top = '50%';
		scrollButton.style.right = '0';
		scrollButton.style.width = '20px';
		scrollButton.style.height = '100px';
		scrollButton.style.border = 'none';
		scrollButton.style.padding = 0;
		scrollButton.style.margin = 0;
		scrollButton.style.marginTop = '-50px'
		scrollButton.style.zIndex = '9999';
		scrollButton.useMap = '#scroller21593';
		document.body.appendChild(scrollButton);
		sS.scrollerImg = document.getElementById('superScrollerImg');
	},

	injectMap : function()
	{
		var imageMap, mapArea;
		var mapArray = [['0, 0,19,24','jumpTop','Top'],['0,25,19,49','jumpUp','PgUp'],['0,50,19,74','jumpDn','PgDn'],['0,75,19,99','jumpEnd','Bottom']];
		imageMap = document.createElement('map');
		imageMap.setAttribute('name', 'scroller21593', 0);
		imageMap.id = 'scroller21593';
		for (i=0;i<mapArray.length;i++)
		{
			mapArea = document.createElement('area');
			mapArea.shape = 'rect';
			mapArea.coords = mapArray[i][0];
			mapArea.href = 'javascript:sS.'+mapArray[i][1]+'()';
			mapArea.title = mapArray[i][2];
			imageMap.appendChild(mapArea);
		}
		document.body.appendChild(imageMap);
	},

	addEvent : function(el, evt, fn)
	{
		if(typeof(el) == "string") el = document.getElementById(el);
		if(el == null) return;
		if(el.attachEvent){ el.attachEvent('on'+evt, fn); }
		else
		if(el.addEventListener){
			if(evt == 'mousewheel') el.addEventListener('DOMMouseScroll', fn, true);
			el.addEventListener(evt,fn,true);
		}
		else {el['on'+evt] = fn;}
	},

	delEvent : function(el, evt, fn)
	{
		if(typeof(el) == "string") el = document.getElementById(el);
		if(el == null) return;
		if(el.detachEvent){ el.detachEvent('on'+evt,fn); }
		else
		if(el.removeEventListener){
			if(evt == 'mousewheel') el.removeEventListener('DOMMouseScroll', fn, true);
			el.removeEventListener(evt,fn,true);
		}
		else { el['on'+evt] = null; }
	},

	hltEvent : function(evt)
	{
		if(!evt) var evt = window.event;
		if(evt.stopPropagation) evt.stopPropagation();
		if(evt.preventDefault) evt.preventDefault();
		evt.cancel = true;
		evt.cancelBubble = true;
		evt.returnValue = false;
		return false;
	},

	evtSource : function(evt)
	{
		if(window.event){ return window.event.srcElement; }
		else { return evt.currentTarget; }
	},

	evtTarget : function(evt)
	{
		if(window.event){ return window.event.srcElement; }
		else { return evt.target; }
	},

	hltSelect : function(el)
	{
		if(typeof(el.onselectstart) != 'undefined')
		{ sS.addEvent(el,'selectstart',function(){ return false; }); }
	},

	posInfo: function(evt)
	{
		if(!evt) evt = window.event;
		var m = sS.getMousePosition(evt);
		var s = sS.getScrollPosition();
	},

	getMousePosition : function(evt)
	{
		var x = 0, y = 0;
		if(!evt) evt = window.event;
		if(evt.clientX || evt.clientY) { x = evt.clientX; y = evt.clientY; }
		var position = { 'x' : x, 'y' : y };
		return position;
	},

	getScrollPosition : function()
	{
		var x = 0, y = 0, w = 0, h = 0;
		if(typeof(window.pageYOffset) == 'number')
		{
			x = window.pageXOffset; y = window.pageYOffset;
			w = document.body.scrollWidth; h = document.body.scrollHeight;
		}
		else
		{
			x = sS.docBody.scrollLeft; y = sS.docBody.scrollTop;
			w = sS.docBody.scrollWidth; h = sS.docBody.scrollHeight;
		}
		var position = { 'x' : x, 'y' : y, 'w' : w, 'h' : h };
		return position;
	},

	getWinSize : function()
	{
		var w = 0, h = 0;
		if(typeof(window.innerWidth) == 'number')
		{ w = window.innerWidth-17; h = window.innerHeight; }
		else
		{ w = sS.docBody.clientWidth; h = sS.docBody.clientHeight; }
		var winsize = { 'w' : w, 'h' : h };
		return winsize;
	},

	onResize : function(evt)
	{
		var w = sS.getWinSize();
		sS.winWide = w.w;
		sS.winHigh = w.h;
		sS.deadVZone = w.h/2;
	},

	onKDown : function(evt)
	{

		sS.offScreen();

		sS.modifier = true;

		if(evt)
			sS.modifier = !evt['altKey'];
		else
			sS.modifier = !(event.altKey&&18)

		if(sS.FormTags.indexOf(','+sS.evtTarget(evt).tagName+',')==-1)
		{
			if(evt['ctrlKey']||event.ctrlKey&&17){}
			else
			{
				if(evt.keyCode==36||event.keyCode==36) { sS.jumpTop(); sS.hltEvent(evt); }
				if(evt.keyCode==33||event.keyCode==33) { sS.jumpUp(); sS.hltEvent(evt); }
				if(evt.keyCode==34||event.keyCode==34) { sS.jumpDn(); sS.hltEvent(evt); }
				if(evt.keyCode==35||event.keyCode==35) { sS.jumpEnd(); sS.hltEvent(evt); }
			}
		}
	},

	onKUp : function (evt)
	{
		sS.modifier = true;
	},

	onWheel : function(evt)
	{
		sS.offScreen();
	},

	onMDown : function(evt)
	{
		if(!evt) evt = window.event;

		var m = sS.getMousePosition(evt);
		var s = sS.getScrollPosition();

		sS.offScreen();

		if(!sS.Hovering && (m.x < sS.winWide) && (s.h > sS.winHigh))
		{
			if(evt.button==sS.button)
			if((sS.NoGoTags+sS.FormTags).indexOf(','+sS.evtTarget(evt).tagName+',')==-1)
			if(!sS.modifier)
			{
				document.onselectstart = function () {return false};
				sS.Dragging = true;
				document.body.style.cursor = 'move';
				sS.X = m.x;
				sS.Y = m.y;
			}
		}
	},

	onMMove : function(evt)
	{
		if(!evt) evt = window.event;

		var m = sS.getMousePosition(evt);
		var s = sS.getScrollPosition();

		if((m.x > (sS.winWide - 20))
		&& (m.x < sS.winWide)
		&& (m.y > (sS.deadVZone-50))
		&& (m.y < (sS.deadVZone+50)) ) sS.Scroller('show');
		else sS.Scroller('hide');

		if(sS.Dragging&&(evt.button==sS.button))
		{
			sS.onDrag(evt);
		}
		else
		{
			sS.onMOut();
		}
	},

	onMOut : function(evt)
	{
		if(!evt) evt = window.event;
		if(sS.Dragging&&evt.button==sS.button) sS.onMUp(evt);
		if(sS.Hovering&&sS.evtSource(evt).tagName!='AREA')
		{
			sS.offScreen();
		}
	},

	onMUp : function(evt)
	{
		var s = sS.getScrollPosition();

		if(!evt) evt = window.event;
		if((evt.button==sS.button) && sS.Dragging)
		{
			document.body.style.cursor = 'auto';
			document.onselectstart = null;
			sS.Dragging = false;
		}
	},

	onDrag : function(evt)
	{
		var m = sS.getMousePosition(evt);
		var s = sS.getScrollPosition();

		if(sS.Dragging)
		{
			sS.posInfo(evt);

			sS.delta = [(sS.X-m.x),(sS.Y-m.y)];
			sS.X = m.x;
			sS.Y = m.y;
			scrollBy(sS.delta[0]*sS.scaling,sS.delta[1]*sS.scaling);
		}
	},

	onScroll : function(evt)
	{
		sS.scrollerImg.style.top = document.body.scrollTop+sS.deadVZone;
	},

	jumpTo: function(jumpTarget)
	{
		var s = sS.getScrollPosition();
		var sh = s.h,sy = s.y;
		if(jumpTarget >= sy)
			if((sh-jumpTarget)>sS.winHigh)
				sy+=Math.ceil((jumpTarget-sy)/sS.speed);
			else
				sy+=Math.ceil((jumpTarget-sy-(sh-jumpTarget))/sS.speed);
		else
			sy += Math.floor((jumpTarget-sy)/sS.speed);

		if(sy != sS.offsetTop)
		{
			sS.JumpMove = true;
			scrollTo(s.x,sy);
		}
		else
		{
			sS.offScreen();
		}
		sS.offsetTop = sy;
	},

	jumpTop : function()
	{
		var s = sS.getScrollPosition();
		sS.jumpTarget = 0;
		clearInterval(sS.scrollTmr);
		sS.scrollTmr = setInterval('sS.jumpTo(sS.jumpTarget)',sS.speed);
	},

	jumpUp : function()
	{
		var s = sS.getScrollPosition();
		var nextTarget = s.y - (sS.winHigh-sS.overlap);
		sS.jumpTarget = (nextTarget <= 0?0:nextTarget);
		clearInterval(sS.scrollTmr);
		sS.scrollTmr = setInterval('sS.jumpTo(sS.jumpTarget)',sS.speed);
	},

	jumpDn : function()
	{
		var s = sS.getScrollPosition();
		var nextTarget = s.y+(sS.winHigh-sS.overlap);
		var skipHeight = s.h-sS.deadVZone;
		sS.jumpTarget = (nextTarget >= s.h-sS.winHigh?skipHeight:nextTarget);

		clearInterval(sS.scrollTmr);
		sS.scrollTmr = setInterval('sS.jumpTo(sS.jumpTarget)',sS.speed);
	},

	jumpEnd : function()
	{
		var s = sS.getScrollPosition();

		sS.jumpTarget = s.h-sS.deadVZone;
		clearInterval(sS.scrollTmr);
		sS.scrollTmr = setInterval('sS.jumpTo(sS.jumpTarget)',sS.speed);
	},

	scrollPage : function(whichWay)
	{
		var s = sS.getScrollPosition();

		sS.offsetTop = (whichWay==1?(s.h-sS.winHigh):0);
		sS.step = 32*(100-sS.delay)/100;
		sS.newY = s.y+Math.floor(whichWay*sS.step);
		sS.delta = [s.x,(sS.newY-s.y)];

		if(s.y != sS.offsetTop)
		{
			sS.Hovering = true;
			scrollTo(s.x,sS.newY);
		}
		else
		{
			sS.offScreen();
		}
	},

	Scroller: function(state)
	{
		if(document.getElementById('superScrollerImg'))
		{
		if(state=='show')
		{
			document.getElementById('superScrollerImg').style.display = 'block';
		}
		else
		{
			document.getElementById('superScrollerImg').style.display = 'none';
		}
		}
		if(state=='show')
			sS.scrollerImg.style.display = 'block';
		else
			sS.scrollerImg.style.display = 'none';
	},

	offScreen : function()
	{
		clearInterval(sS.scrollTmr);
		sS.scrollTmr = null;
		sS.docBody.style.scrollbarFaceColor = sS.thumbFace;

		sS.Dragging = false;
		sS.Hovering = false;
		sS.JumpMove = false;
	},

	beforeUnload : function()
	{
		sS.delEvent(window,'resize',sS.onResize);
		aS.delEvent(document,'mousewheel',sS.onWheel);
		sS.delEvent(document,'mousedown',sS.onMDown);
		sS.delEvent(document,'mousemove',sS.onMMove);
		sS.delEvent(document,'mouseup',sS.onMUp);
		sS.delEvent(document,'keydown',sS.onKDown);
		sS.delEvent(document,'keyup',sS.onKUp);
	}
}
sS.init();
